The Asti Spumante Bar Code





4.00/5 (7 votes)
An interesting article to learn how UPC-A bar coding works
Introduction
I've decided to write this article after reading the novel 'THE ASTI SPUMANTE CODE' by Toby Clements, which is a parody of 'THE DA VINCI CODE' by Dan Brown. I'm not that obsessed with any of these books, but just thought it would be more interesting to introduce UPC-A barcoding from such a perspective; though sarcastic.
Almost every item we buy or own has a barcode printed on it. We see those barcodes every day, but still we don't understand what they really mean or how to generate them. The major benefit of using barcodes is to automate and improve the speed and accuracy of data collection. That's why we see them on most sellable items.
One other way to look at barcodes is to think of them as one other form of cryptography that's so easy to decipher using barcode scanners. For example, a UPC-A barcode is a simple encoding of a 12 digit number into its bit representation, where 1 is represented as black vertical line and 0 represented as white vertical line. We will be creating a Java program that just does that.
Note: Image Cropped From 'THE ASTI SPUMANTE CODE' Book Cover
Background
In 'The Da Vinci Code', the secret that Robert Langdon and Sophie were searching for was the Holy Grail, which the Priory of Sion has hidden for centuries. However, in 'The ASTI SPUMANTE CODE', the secret that James Crack and Emily were searching for was the greatest book that will ever be written. According to Toby Clements, 'the secret ingredients of this book - characterization, plot, setting, and so forth - what para-literalists call the Asti Spumante Code - are contained on something called the Mure-de-Paume, the legendary keystone.'
While searching for the code, James Crack and Emily find a prolix, or simply what I concluded, a book. They discover under the book's red leather cover 'a rectangle of paper approximately five centimeters by three, laminated to the back of the prolix. On the piece of paper were a set of lines of differing widths and heights that could be read from right to left, or left to right, or not at all. It was a code. A barcode.' As sarcastic as this can get, it does describe what a barcode looks like.
In order to be able to read the barcode, James Crack escapes to London to a bookstore owned by Donnie Dogs. Clark asks Dogs about barcodes, and Dogs explains that barcodes are named by scholars as UPC, or Universal Product Code. Manufactures buy those barcodes from UCC, or Uniform Code Council. The UPC is made up of exactly 12 digits. Each digit is represented as a stream of 7 bits, and each bit corresponds to a slice (1 for black slices and 0 for white ones). The first 6 digits for the 12-digit UPC correspond to the manufacturer code, and they are handed down by UCC. The next 5 digits correspond to the product code, and they are filled by the manufacturer. The last digit is a check digit used to help the barcode scanner make sure that it read the right code number. And as we've all seen, in a bookstore or super market, a scanner reads the barcode through red laser beams (i.e. barcode reader). In 'The ASTI SPUMANTE CODE', it is this check digit that James and Emily have to calculate in order to reach the hidden secret. Wow, what an impossible mission!
The check digit is calculated by first adding the odd-spaced digits (6 characters), multiplying them by three, then adding them to the sum of the even-spaced digits (5 characters since we exclude the check digit). Then subtract from the next higher multiple of 10.
For example, let's say we want to find the check digit for the following code: 31415926535.
3 * (3 + 4 + 5 + 2 + 5 + 5) + (1 + 1 + 9 + 6 + 3) = 3 * (24) + (20) = 92
==> Check code = 100 - 92 = 8.
Overview
There are many kinds of barcodes:
- Codabar
- Code 128
- Code 3 of 9
- Code 93
- EAN 13
- EAN 8
- Interleabed 2/5
- MSI/Plessey
- Postal/Postnet
- UPC-A
- UPC-E
The kind that Toby Clements refers to in his parody is UPC-A. In the UPC code, only the digits [0-9] are allowed. However, in other types of barcoding, you might have characters, symbols, or even images!
UPC-A
In addition to the information that Dogs mentioned, there remains some useful information that we need to know about the UPC-A barcode.
Structure of UPC-A Barcode
We can divide the 12 digit UPC code into two parts: the left 6 digits and the right 6 digits. Every digit has its predefined stream of bits based on whether it is a left or a right digit.
Digit | Bits for Left Digits | Bits for Right Digits |
0 | 0001101 | 1110010 |
1 | 0011001 | 1100110 |
2 | 0010011 | 1101100 |
3 | 0111101 | 1000010 |
4 | 0100011 | 1011100 |
5 | 0110001 | 1001110 |
6 | 0101111 | 1010000 |
7 | 0111011 | 1000100 |
8 | 0110111 | 1001000 |
9 | 0001011 | 1110100 |
For example, the left 3 in the following code 314159265358 would be converted into 0111101, while the right 3 would be converted into 1000010.
The left, middle, and right codes are used to help the scanner (or reader) identify where the code starts and ends. The number system is a single digit which identifies the type of the product.
Number System | Description |
0 |
Regular UPC codes |
1 |
Reserved |
2 |
Weight items marked at the store |
3 |
National Drug/Health-related code |
4 |
Non-Food items |
5 |
Coupons |
6 |
Reserved |
7 |
Regular UPC codes |
8 |
Reserved |
9 |
Reserved |
The remaining digits should be well known by now, as explained by Dogs and as shown in the figure.
The Program
This program converts a 12 digit code into a barcode. The whole idea is very simple: read a digit, convert it to its corresponding 7 bits based on whether it is on the left or the right, and then draw a vertical line for every 1, and skipping space for every 0. The program also includes a feature to let you calculate the check digit. In case you have entered a wrong check digit, the program doesn't display a barcode.
Program View
UPC is the number entered by the user, and barcode is the alternating black and white lines (or slices) that we want to generate.
How To Run The Program
I have used BlueJ as the environment to implement this program. So if you have BlueJ, you can easily open it, view the UML diagram, and run the Main
class. Otherwise, you can always run the *.jar file or execute the Run.bat file.
Using the Code
As shown in the figure above, the Main
class uses the ASBarcode
class, which is the major class that contains all the program's logic. The ASBarcode
uses the UPCField
and BarcodeLabel
classes. The UPCField
class inherits from the MNDigitField
class, which represents a text field that allows only digits and up to maximum of N
digits. This class also has two component actors (MComponentActor
and NComponentActor
) which act on two components (MComponent
and NComponent
). In our case, the MComponent
is the 'Generate Check Digit' button, the NComponent
is the 'Generate Barcode' button, and the action that the MComponentActor
and NComponentActor
do is enable or disable the buttons.
GUI Behavior
We have a panel (ASBarcode
) containing a text field (UPCField
) where the user can enter UPC-A code, a barcode label (BarcodeLabel
) generated when the user clicks "Generate Bar Code" button, a label ("Enter UPC"), and two buttons ("Generate check Digit" and "Generate bar Code"). The two buttons are initially disabled. Once the user types 11 characters in the UPC-A field (UPCField
), the "Generate Check Digit" button becomes enabled. The user will then click this button, and the check digit will be generated. As a result, the UPC field will now contain 12 characters, and thus the "Generate Check Digit" buttons gets disabled and the "Generate Bar Code" button gets enabled. Now, the user would click on the "Generate Bar Code" button, and the barcode will be generated based on the UPC-A code specified in the UPC field. However, before generating the barcode label, the program checks if the UPC-A code entered by the user is valid (UPC-A is valid if it is a 12 digit number and the value of the check digit is valid). In case the UPC-A code is invalid, nothing is displayed on the barcode label.
Class Deign
ASBarcode
- The
codeProjectOrange
variable represents the orange color used at The Code Project, whose RGB components are Red = 255, Green = 153, and Blue = 0. - The
barcodeLabel
is a reference to theBarcodeLabel
object that will display the generated barcode. - The
barcodePanel
is the panel that will hold theBarcodeLabel
component. - The two variables
generateCheckDigitButton
andgenerateBarcodeButton
are references toJButton
objects, and will both fire anActionEvent
when the user clicks them. TheCheckDigitListener
andBarcodeListener
classes will handle those events. - The
buttonPanel
is a panel that will hold the two buttons. - The
upcField
is a reference to the field where the user enters the UPC code. - The
upcPanel
is the panel that will hold this field.
The logic of the program is found in the ASBarcode()
constructor, and the main method is used to test the ASBarcode
class.
Initialization
-
Create the Barcode Label with a slice width of 2 pixels and a slice height of 150 pixels. Let the color of slices (1) be black and of empty space (0) be orange. In case there is any other number (other than 0 or 1), then draw the red color to reflect that something went wrong. Add the barcode label to its panel.
barcodeLabel = new BarcodeLabel (2, 150, Color.black, codeProjectOrange, Color.red);
- Create the 'Generate Check Digit' and 'Generate Bar Code' and add them to their panel. Also, add action listeners (
CheckDigitListener
andBarcodeListener
) to them, and make them initially disabled. - Create the UPC field and pass to it as arguments the
generateCheckDigitButton
andgenerateBarcodeButton
buttons. Those will be the components on which theMComponentActor
andNComponentActor
will act on. Don't get confused, this will be explained in more details under theUPCField
andMNDigitField
classes. - At last, add all those components to the
ASBarcode
panel.
CheckDigitListener
The method below is called when the 'Generate Check Digit' button is clicked.
void actionPerformed (ActionEvent e)
{
// Generate the check digit and append it at the end of the 11-digit UPC field
upcField.generateCheckDigit ();
}
BarcodeListener
The method below is called when the 'Generate Bar Code' button is clicked. If the check digit is valid, the barcode is generated and displayed.
public void actionPerformed (ActionEvent e)
{
// Generate the barcode only if the check digit is valid
if (upcField.isCheckDigitValid ())
{
// Set the UPC of the barcode label
barcodeLabel.setUPC (upcField.getUPC());
// Validate the UPC of the barcode label
barcodeLabel.validateUPC ();
// Generate the barcode
barcodeLabel.generateBarcode ();
// Select the text in the UPC field
upcField.selectAll ();
}
else
{
// Make the barcode as invalid so that nothing would be drawn on
// the barcode panel.
// Check BarcodeLabel.paintComponent
barcodeLabel.setValid (false);
}
}
BarcodeLabel
Constants
We first start by defining the constants:
// Put in front and at end of every barcode
final String quiteZone = "000000000";
// Put after quite zone at the front - See Figure
final String leftStartCode = "101";
// Put before quite zone at the end - See Figure
final String rightEndCode = "101";
// Put in the center of every barcode - See Figure
final String centerCode = "01010";
// Represent the left UPC bits for the digits
final String leftCodes[] = {"0001101", "0011001", "0010011", "0111101",
"0100011", "0110001", "0101111", "0111011",
"0110111", "0001011"};
// Represent the right UPC bits for the digits
final String rightCodes[] = {"1110010", "1100110", "1101100", "1000010",
"1011100", "1001110", "1010000", "1000100",
"1001000", "1110100"};
// represents the number of slices in a UPC-A
final int sliceNum = 113; // 3 + 3 + 5 + (12 * 7) + (9 * 2) = 113
The quite zone, left, center, and right codes will be added to every barcode we are going to generate.
We would care to know the number of slices we have in order to define the widths of the slices and of the panel that will hold them. The sliceNum
is a constant equal to 113
. This is the sum of the left, center, right codes (3 + 5 + 3), the 12 digits, where each digit is made up of 7 slices or bits (12 * 7), and the quite zone (9 * 2).
Instance Variables
String UPC; // UPC to be converted into barcode
String barcode; // the barcode
boolean valid; // UPC is valid or not?
Color barColor; // The color of the slice corresponding to bit 1
Color spaceColor; // The color of the slice corresponding to bit 0
Color errorColor; // In case the bit is neither 0 or 1 (something wrong)
int x; // Represents the current x coordinate of the slice
int sliceWidth; // Represents the width of the slice
int width; // Width of barcode label
int height; // height of barcode label
Methods
The constructor sets the color and size of the barcode label.
//---------------------------------------------------------------------
// Constructor...
//
// sw is the slice width and sh is the slice height.
// bc is the bar color, sc is the space color, and ec is error color.
//---------------------------------------------------------------------
public BarcodeLabel (int sw, int sh, Color bc, Color sc, Color ec)
{
// Upc is initially invalid
valid = false;
// Set x initially to zero
x = 0;
// Set the slicewidth
sliceWidth = sw;
// Set the width of barcode label
width = sliceNum * sw;
// Set the height of barcode label
height = sh;
// Set the colors
barColor = bc;
spaceColor = sc;
errorColor = ec;
// Set the background color to space color
this.setBackground (spaceColor);
// Set the preferred size of the barcode label
this.setPreferredSize (new Dimension (width, height));
}
The paintComponent()
method draws the barcode label by first clearing the background and then only drawing the slices if the UPC code is valid.
//---------------------------------------------------------------------
// Paints the barcode only if it is valid...
//---------------------------------------------------------------------
public void paintComponent (Graphics page)
{
super.paintComponent (page);
// Clear the barcode before drawing
page.setColor (getBackground ());
page.fillRect (0, 0, width, height);
// Draw the barcode only if the UPC is valid
if (isValid ())
drawBarcode (page);
}
This method takes care of drawing the vertical slices over the label.
//---------------------------------------------------------------------
// Draws the barcode if it is not null.
//---------------------------------------------------------------------
public void drawBarcode (Graphics page)
{
int barcodeLength;
// Set x to zero
x = 0;
if (barcode != null)
{
// Get the barcode length
barcodeLength = barcode.length ();
// Loop over every character (0 or 1)
for (int i = 0; i < barcodeLength; i++)
{
// Draw a white slice for the 0
if (barcode.charAt (i) == '0')
{
page.setColor (spaceColor);
}
// Draw a black slice for the '1'
else if (barcode.charAt (i) == '1')
{
page.setColor (barColor);
}
// Draw a red slice to show something graphically
else
{
page.setColor (errorColor);
}
// Update the coordinates
x += sliceWidth;
// Draw the slices at the specified coordinates
page.fillRect (x, 0, sliceWidth, height);
}
}
}
The UPC must be exactly 12 digits before we can generate the barcode from it.
//---------------------------------------------------------------------
// Checks if the UPC is valid. a UPC is valid if it consists
// of exactly 12 digits.
//---------------------------------------------------------------------
public void validateUPC ()
{
valid = UPC.matches ("[0-9]{12}?");
}
The major method that generates the barcode from the UPC field.
//---------------------------------------------------------------------
// Generate the barcode from the UPC...
//---------------------------------------------------------------------
public void generateBarcode ()
{
if (isValid ())
{
barcode = quiteZone + leftStartCode +
leftCodes[charToInteger (UPC.charAt (0))] +
leftCodes[charToInteger (UPC.charAt (1))] +
leftCodes[charToInteger (UPC.charAt (2))] +
leftCodes[charToInteger (UPC.charAt (3))] +
leftCodes[charToInteger (UPC.charAt (4))] +
leftCodes[charToInteger (UPC.charAt (5))] +
centerCode +
rightCodes[charToInteger (UPC.charAt (6))] +
rightCodes[charToInteger (UPC.charAt (7))] +
rightCodes[charToInteger (UPC.charAt (8))] +
rightCodes[charToInteger (UPC.charAt (9))] +
rightCodes[charToInteger (UPC.charAt (10))] +
rightCodes[charToInteger (UPC.charAt (11))] +
rightEndCode + quiteZone;
repaint ();
}
}
UPCField
Methods
Calls the parent (MNDigitField
) constructor to create a text field that only accepts digits with a maximum of N
(12) digits. When exactly M
(11) digits are entered, the MComponent
('Generate Check Digit' button) is acted upon (enabled). Otherwise, the action is undone (button disabled). When exactly N
(12) digits are entered, the NComponent
('Generate Bar Code' button) is acted upon (enabled). Otherwise, the action is undone (button disabled).
//---------------------------------------------------------------------
// Create a field where user enters UPC code.
//---------------------------------------------------------------------
public UPCField (JButton MButton, JButton NButton)
{
// Create a 12 digit field having width of 8 cols
// M = 11, N = 12, MComponent = MButton, NComponent = NButton
// cols = 8.
super (11, 12, MButton, NButton, 8);
}
If the UPC is 11 digits long, then generate the check digit, and append it to the end of the UPC to form the 12 digit valid UPC.
//---------------------------------------------------------------------
// Generates check digit and appends it to the upc field.
//---------------------------------------------------------------------
public void generateCheckDigit ()
{
// Generate check digit only if there are 11 characters
if (this.howManyDigits () == 11)
{
String upc = this.getText ();
int checksum = 0;
checksum = generateCheckDigit (upc);
// Append the check digit to the end of hte UPC
this.setText (upc + checksum);
}
}
Generates the check digit from the first 11 digits of the UPC field.
//---------------------------------------------------------------------
// Generates check digit.
//---------------------------------------------------------------------
public int generateCheckDigit (String upc)
{
int checksum = 0;
for (int i = 1; i <= upc.length (); i++)
{
// even
if (i % 2 == 0)
checksum += charToInteger (upc.charAt (i - 1)) * 1;
// odd
else
checksum += charToInteger (upc.charAt (i - 1)) * 3;
}
return ( 10 - ( checksum % 10 ) ) % 10;
}
Tells whether the check digit is valid.
//---------------------------------------------------------------------
// Makes sure that the check digit is valid.
//---------------------------------------------------------------------
public boolean isCheckDigitValid ()
{
if (howManyDigits () == 12)
{
String upc = this.getText ();
// The check digit entered by the user
// character 12 (start at 0)
int checkDigitEntered = charToInteger (upc.charAt (11));
// the generate (valid) check digit
int validCheckDigit = this.generateCheckDigit (upc.substring (0, 11));
return checkDigitEntered == validCheckDigit;
}
return false;
}
MNDigitField
This is a class that allows you to create a text field with only digits and with a maximum of N
digits. Once the number of digits becomes M
, an MAction
is performed on the MComponent
. And once the number of digits is not M
anymore, an MReaction
is performed. The same is true for N
. Once the number of digits becomes N
, an NAction
is performed on the NComponent
, and once the number of digits is not N
anymore, an NReaction
is performed.
public MNDigitField (int m, int n, JComponent mComp, JComponent nComp, int cols)
{
// Specify the width of the text field in terms of columns
super (cols);
// Set M and N
this.M = m;
this.N = n;
// create component actors
this.MComponentActor = new ComponentActor (mComp);
this.NComponentActor = new ComponentActor (nComp);
// Set the action type to ENABLE (This is default type, but I'm
// resetting to emphasize the idea)
this.MComponentActor.setActionType (ComponentActor.ENABLE);
this.NComponentActor.setActionType (ComponentActor.ENABLE);
// Add document listener to the text field
this.getDocument().addDocumentListener (new MNDocumentListener ());
}
The NDigitDocument
class is responsible for not allowing characters other than digits to be entered, and for not allowing the number of characters to exceed N
.
static class NDigitDocument extends PlainDocument
{
public void insertString (int offs, String str, AttributeSet a)
throws BadLocationException
{
if (str == null)
return;
// Don't allow number of characters to exceed N
// (The +1 is because insertString is called before insertupdate)
if (currentLength + 1 > N)
return;
// Validate that the characters of the string are digits
for (int i = 0; i < str.length(); i++)
{
if (!Character.isDigit (str.charAt (i)))
return;
}
super.insertString(offs, str, a);
}
}
The MNDocumentListener
class listens to the user's interaction with the textfield
, and decides what to do based on the number of characters in the text field.
class MNDocumentListener implements DocumentListener
{
//-----------------------------------------------------------------
// Called when users insert characters.
//-----------------------------------------------------------------
public void insertUpdate (DocumentEvent e)
{
decide (e);
}
//-----------------------------------------------------------------
// Called when users remove characters (DEL or Back Space).
//-----------------------------------------------------------------
public void removeUpdate (DocumentEvent e)
{
decide (e);
}
//-----------------------------------------------------------------
// Do an action based on the values of M and N. In our case, the
// action is to enable or disable (reaction) the MComponent
// and NComponent.
//-----------------------------------------------------------------
public void decide (DocumentEvent e)
{
Document doc = (Document)e.getDocument();
currentLength = doc.getLength ();
// Enable MComponent if M digits reached
// Otherwise, disable it.
MComponentActor.decide (currentLength == M);
// Enable NComponent if N digits reached
// Otherwise, disable it.
NComponentActor.decide (currentLength == N);
}
}
Actor
This is an abstract
class that performs an action and reverses this action based on a condition. The action performed is based on the actionType
.
public void decide (boolean condition)
{
if (condition)
doAction ();
else
undoAction ();
}
ComponentActor
This class inherits from the Actor abstract
class. It acts on a Java GUI component. If the actionType
is ENABLE
, then this class would enable or disable a JComponent
based on a condition.
The method called in our program to enable the 'Generate Check Digit' and 'Generate Bar Code' buttons is:
//---------------------------------------------------------------------
// Perform an action.
//---------------------------------------------------------------------
public void doAction ()
{
// Do nothing if no component is supplied
if (component == null)
return;
// Perform action based on action type
switch (actionType)
{
case ENABLE:
component.setEnabled (true);
break;
case MAKE_VISIBLE:
component.setVisible (true);
break;
}
}
The method called in our program to disable the 'Generate Check Digit' and 'Generate Bar Code' buttons is:
//---------------------------------------------------------------------
// Reverse the action..
//---------------------------------------------------------------------
public void undoAction ()
{
// Do nothing if no component is supplied
if (component == null)
return;
// Perform reaction based on action type
switch (actionType)
{
case ENABLE:
component.setEnabled (false);
break;
case MAKE_VISIBLE:
component.setVisible (false);
break;
}
}
Conclusion
I created this program and wrote the article in 2005. I got it submitted to Code Project, but at that time Java was not supported on this site. I guess now I got back the opportunity to share it with the community. I hope it would be fun... Enjoy!
Just in case you wondered what ASTI SPUMANTE means. It is a "semi-dry sparkling wine produced from the Moscato di Canelli grape in the village of Asti, in the Piedmont region of Italy".
Revision History
- 06/01/2008: Original article submitted